package ru.niir.goodfil.db;

import org.apache.commons.lang.StringUtils;
import ru.niir.goodfil.db.dic.*;
import ru.niir.goodfil.db.handlers.Goodfil;
import ru.niir.goodfil.utils.SumFormat;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import static ru.niir.goodfil.utils.Utils.s;

/**
 * Заказ. Заказ может быть оформлен либо клдиентом самостоятельно либо менеджером за клиента.
 */
@Entity
@Table(name = "`Orders`")
public class Order extends PropertyBag implements Unique, Serializable {
    /**
     * Идентификатор заказа
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "`Id`")
    private long id = -1;

    /**
     * Идентификатор клиента, на которого оформлен заказ
     */
    @Column(name = "`IdClient`")
    private long clientId = -1;

    /**
     * Идентификатор менеджера, который курирует заказ
     */
    @Column(name = "`IdManager`")
    private long managerId = -1;


    /**
     * Статус заказа. Статус показывает на каком этапе в цепочке обработки заказов находится данный заказ. Перечень
     * статусов заказов находится в классе OrderState и таблице dic_OrderStates.
     *
     * @see ru.niir.goodfil.db.dic.OrderState
     */
    @Column(name = "`IdOrderState`")
    private int orderStateId = OrderState.PRE_SAVED;

    /**
     * Тип доставки. Указывает на способ доставки для данного заказа. Перечень типов доставки находится в классе
     * DeliveryType и таблице dic_DeliveryTypes.
     *
     * @see ru.niir.goodfil.db.dic.DeliveryType
     */
    @Column(name = "`IdDeliveryType`")
    private int deliveryTypeId = DeliveryType.SELF_DELIVERY;

    /**
     * Тип заказа (банк или касса).
     *
     * @see ru.niir.goodfil.db.dic.OrderType
     */
    @Column(name = "`IdOrderType`")
    private int orderTypeId = OrderType.BANK;

    /**
     * Промежуток времени (в днях), в течение которого заказ должен быть доставлен клиенту
     */
    @Column(name = "`DeliveryTimeSpan`")
    private int deliveryTimeSpan = 0;

    /**
     * Адрес, по которому заказ должен быть доставлен. При создании заказа адрес доставки берется из профиля клиента.
     * Поле может не иметь смысла для некоторых типов доставки (например для самовывоза).
     */
    @Column(name = "`DeliveryAddress`")
    private String deliveryAddress = "";

    /**
     * Стоимость доставки
     */
    @Column(name = "`DeliverySum`")
    private float deliverySum = 0;


    /**
     * Скидка в процентах на заказ.
     *
     * @deprecated Поле не используется, т.к. Заказчик отказался от системы скидок
     */
    @Deprecated
    @Column(name = "`DiscountPercent`")
    private float discountPercent = 0;

    /**
     * Скидка в рублях на заказ.
     *
     * @deprecated Поле не используется, т.к. Заказчик отказался от системы скидок
     */
    @Deprecated
    @Column(name = "`DiscountAbs`")
    private float discountAbs = 0;


    /**
     * Флаг, показывающий, что заказ был изменем.
     */
    @Column(name = "`IsDeleted`")
    private boolean isDeleted = false;

    /**
     * Дата создания заказа
     */
    @Column(name = "`CreationDate`", nullable = false)
    private Timestamp creationDate = GoodfilUtils.getCurrentTimestamp();

    /**
     * Дата истечения резервирования
     */
    @Column(name = "`ReservationDate`", nullable = false)
    private Timestamp reservationDate = GoodfilUtils.getCurrentTimestamp();

    /**
     * Дата отгрузки
     */
    @Column(name = "`DeliveryDate`", nullable = true)
    private Timestamp deliveryDate;

    /**
     * Номер заказа в 1С
     */
    @Column(name = "`1CNum`", nullable = true)
    private String c1Num;

    /**
     * Номер накладной
     */
    @Column(name = "`NoteNum`")
    private String noteNum = "";

    /**
     * Дата оплаты заказа с 1С
     */
    @Column(name = "`1CPaymentDate`", nullable = true)
    private Date c1PaymentDate;

    @Column(name = "`Firm`", nullable = true)
    private int firm = 0;

    @Column(name = "StorekeeperId", nullable = false)
    private long storekeeperId = -1;

    @Column(name = "Sequence")
    private String sequence;

    /**
     * Дата отгрузки
     */
    @Column(name = "AssemblyDate", nullable = true)
    private java.util.Date assemblyDate;

    /**
     * Причины срыва
     */
    @Column(name = "FailureCauseId", nullable = false)
    private int failureCauseId = -1;

    @Column(name = "AssemblyBlock", nullable = false)
    private boolean assemblyBlock = false;

    /**
     * Фактическая дата отгрузки
     */
    @Column(name = "FactDeliveryDate", nullable = true)
    private java.util.Date factDeliveryDate;

    @Column(name = "ChangeDate")
    private java.util.Date changeDate;

    @Column(name = "MainOrderId")
    private String mainOrderId;

    @Column(name = "IsAdditional", nullable = false)
    private boolean isAdditional = false;

    /**
     * Сумма по всем позициям заказа
     */
    @Transient
    private float sum;

    /**
     * Количество позиций в заказе
     */
    @Transient
    private int positionsCount;

    /**
     * Клиент, на которого оформлен заказ
     */
    @Transient
    private Client client;

    /**
     * Менеджер ведущий заказ
     */
    @Transient
    private User manager;

    /**
     * Расширенная информация о доставке
     */
    @Transient
    private OrderDeliveryInfoExt deliveryInfoExt = new OrderDeliveryInfoExt();

    /**
     * Ответственный за сборку
     */
    @Transient
    private User storekeeper;

    @Transient
    private double orderWeight;

    @Transient
    private double orderVolume;

    @Transient
    private String driverInfo;

    @Transient
    private float factSum;

    @Transient
    private String deliveryComment;

    @Transient
    private String adress;

    @Transient
    private boolean packageCountMultiplies;

    @Transient
    private java.util.Date expectedAssembyDate;

    @Transient
    private java.util.Date expectedDeliveryDate;

    public String getMainOrderId() {
        return mainOrderId;
    }

    public void setMainOrderId(String mainOrderId) {
        this.mainOrderId = mainOrderId;
    }

    public boolean isAdditional() {
        return isAdditional;
    }

    public void setAdditional(boolean isAdditional) {
        this.isAdditional = isAdditional;
    }

    public long getMainOrderIdAsLong(){
        if(mainOrderId == null) return -1;
        return Long.parseLong(mainOrderId);
    }

    public java.util.Date getExpectedDeliveryDate() {
        return expectedDeliveryDate;
    }

    public void setExpectedDeliveryDate(java.util.Date expectedDeliveryDate) {
        this.expectedDeliveryDate = expectedDeliveryDate;
    }

    public java.util.Date getExpectedAssembyDate() {
        return expectedAssembyDate;
    }

    public void setExpectedAssembyDate(java.util.Date expectedAssembyDate) {
        this.expectedAssembyDate = expectedAssembyDate;
    }

    public boolean isPackageCountMultiplies() {
        return packageCountMultiplies;
    }

    public void setPackageCountMultiplies(boolean packageCountMultiplies) {
        this.packageCountMultiplies = packageCountMultiplies;
    }

    public java.util.Date getChangeDate() {
        return changeDate;
    }

    public String getPackageCountMultipliesAsString() {
        return packageCountMultiplies ? "КГТ" : "";
    }

    public void setChangeDate(java.util.Date changeDate) {
        this.changeDate = changeDate;
    }

    public String getChangeDateAsString() {
        return ru.niir.goodfil.utils.DateFormat.FormatDate(changeDate);
    }

    public boolean isChangeDateNull() {
        return changeDate == null;
    }

    public java.util.Date getFactDeliveryDate() {
        return factDeliveryDate;
    }

    public void setFactDeliveryDate(java.util.Date factDeliveryDate) {
        this.factDeliveryDate = factDeliveryDate;
    }

    public float getFactSum() {
        return factSum;
    }

    public String getAdress() {
        return adress;
    }

    public void setAdress(String adress) {
        this.adress = adress;
    }

    public String getDeliveryComment() {
        return deliveryComment;
    }

    public void setDeliveryComment(String deliveryComment) {
        this.deliveryComment = deliveryComment;
    }

    public void setFactSum(float factSum) {
        this.factSum = factSum;
    }

    public String getDriverInfo() {
        return driverInfo;
    }

    public void setDriverInfo(String driverInfo) {
        this.driverInfo = driverInfo;
    }

    public double getOrderWeight() {
        return orderWeight;
    }

    public void setOrderWeight(double orderWeight) {
        this.orderWeight = orderWeight;
    }

    public double getOrderVolume() {
        return orderVolume;
    }

    public void setOrderVolume(double orderVolume) {
        this.orderVolume = orderVolume;
    }

    public int getFailureCauseId() {
        return failureCauseId;
    }

    public void setFailureCauseId(int failureCauseId) {
        this.failureCauseId = failureCauseId;
    }

    public boolean isAssemblyBlock() {
        return assemblyBlock;
    }

    public void setAssemblyBlock(boolean assemblyBlock) {
        this.assemblyBlock = assemblyBlock;
    }

    public String getFailureCauseAsString() {
        return FailureCause.asString(failureCauseId);
    }

    public String getSumAsString() {
        return SumFormat.formatSum("###,###,##0.00", sum);
    }

    public String getFactSumAsString() {
        return SumFormat.formatSum("###,###,##0.00", factSum);
    }

    public String getSequence() {
        return sequence;
    }

    public void setSequence(String sequence) {
        this.sequence = sequence.equals("") ? null : sequence;
    }

    /**
     * Расширенная информация о доставке
     */
    public OrderDeliveryInfoExt getDeliveryInfoExt() {
        return deliveryInfoExt;
    }

    /**
     * Расширенная информация о доставке
     */
    public void setDeliveryInfoExt(OrderDeliveryInfoExt deliveryInfoExt) {
        this.deliveryInfoExt = deliveryInfoExt;
    }

    public Client getClient() {
        return client;
    }

    public void setClient(Client client) {
        assert client != null;
        assert client.getId() == clientId;

        this.client = client;
    }

    public User getManager() {
        return manager;
    }

    public void setManager(User manager) {
        assert manager != null;
        assert manager.getId() == managerId;

        this.manager = manager;
    }

    public User getStorekeeper() {
        return storekeeper;
    }

    public void setStorekeeper(User storekeeper) {
        assert storekeeper != null;
        assert storekeeper.getId() == storekeeperId;
        this.storekeeper = storekeeper;
    }

    //
    //  ------------------------------------------------------------------------------------
    //

    public long getId() {
        return id;
    }

    /**
     * Возвращает идентификатор заказа в виде строки. Если идентификатор не установлен (т.е. равен -1) будет возвращена
     * пустая строка.
     *
     * @return идентификатор заказа в виде строки
     */
    public String getIdAsString() {
        return id == -1 ? "" : String.valueOf(id);
    }


    public void setId(long id) {
        this.id = id;
    }

    public long getClientId() {
        return clientId;
    }

    public void setClientId(long clientId) {
        this.clientId = clientId;
    }

    public long getManagerId() {
        return managerId;
    }

    public void setManagerId(long managerId) {
        this.managerId = managerId;
    }

    public int getOrderStateId() {
        return orderStateId;
    }

    public String getOrderStateAsString() {
        return OrderState.asString(orderStateId);
    }

    /**
     * @param orderStateId
     * @deprecated Этот метод не делает ничего
     */
    public void setOrderStateId(int orderStateId) {
        this.orderStateId = orderStateId;
    }

    public int getDeliveryTypeId() {
        return deliveryTypeId;
    }

    public String getDeliveryTypeAsString() {
        return DeliveryType.asString(deliveryTypeId);
    }

    public void setDeliveryTypeId(int deliveryTypeId) {
        this.deliveryTypeId = deliveryTypeId;
    }

    public int getOrderTypeId() {
        return orderTypeId;
    }

    public String getOrderTypeAsString() {
        return OrderType.asString(orderTypeId);
    }

    public void setOrderTypeId(int orderTypeId) {
        this.orderTypeId = orderTypeId;
    }

    public int getDeliveryTimeSpan() {
        return deliveryTimeSpan;
    }

    public String getDeliveryTimeSpanString() {
        if (deliveryTimeSpan == 1) {
            return "1 день";
        }
        if (deliveryTimeSpan == 2) {
            return "2 дня";
        }
        if (deliveryTimeSpan == 3) {
            return "3 дня";
        }
        if (deliveryTimeSpan == 4) {
            return "4 дня";
        }
        return String.valueOf(deliveryTimeSpan) + " дней";
    }

    public void setDeliveryTimeSpan(int deliveryTimeSpan) {
        this.deliveryTimeSpan = deliveryTimeSpan;
    }

    public String getDeliveryAddress() {
        return deliveryAddress;
    }

    public void setDeliveryAddress(String deliveryAddress) {
        this.deliveryAddress = s(deliveryAddress);
    }

    public float getDeliverySum() {
        return deliverySum;
    }

    public void setDeliverySum(float deliverySum) {
        this.deliverySum = deliverySum;
    }

    public float getDiscountPercent() {
        return discountPercent;
    }

    public void setDiscountPercent(float discountPercent) {
        this.discountPercent = discountPercent;
    }

    public float getDiscountAbs() {
        return discountAbs;
    }

    public void setDiscountAbs(float discountAbs) {
        this.discountAbs = discountAbs;
    }

    public boolean isDeleted() {
        return isDeleted;
    }

    public void setDeleted(boolean deleted) {
        isDeleted = deleted;
    }

    public Timestamp getCreationDate() {
        return creationDate;
    }

    public String getCreationDateAsString() {
        if (creationDate == null) {
            return StringUtils.EMPTY;
        }
        return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(creationDate);
    }

    public String getDeliveryDateAsString() {
        if (deliveryDate == null) {
            return StringUtils.EMPTY;
        }
        return new SimpleDateFormat("dd.MM.yyyy").format(deliveryDate);
    }

    public void setCreationDate(Timestamp creationDate) {
        this.creationDate = creationDate;
    }

    public Date getDeliveryDate() {
        if (deliveryDate == null) {
            return null;
        }
        return new Date(deliveryDate.getTime());
    }

    public java.util.Date getDeliveryDateAsJavaUtilDate() {
        if (deliveryDate == null) {
            return null;
        }
        return new java.util.Date(deliveryDate.getTime());
    }

    public void setDeliveryDateAsJavaUtilDate(java.util.Date deliveryDate) {
        if (deliveryDate == null) {
            this.deliveryDate = null;
        } else {
            this.deliveryDate = new Timestamp(deliveryDate.getTime());
        }
    }

    public void setDeliveryDate(java.util.Date deliveryDate) {
        if (deliveryDate == null) {
            this.deliveryDate = null;
        } else {
            this.deliveryDate = new Timestamp(deliveryDate.getTime());
        }
    }

    public void setDeliveryDate(java.sql.Date deliveryDate) {
        if (deliveryDate == null) {
            this.deliveryDate = null;
        } else {
            this.deliveryDate = new Timestamp(deliveryDate.getTime());
        }
    }

    public Timestamp getReservationDate() {
        return reservationDate;
    }

    public void setReservationDate(Timestamp reservationDate) {
        this.reservationDate = reservationDate;
    }

    public java.util.Date getReservationDateAsDate() {
        return new Date(reservationDate.getTime());
    }

    public void setReservationDateAsDate(java.util.Date reservationDate) {
        this.reservationDate = new Timestamp(reservationDate.getTime());
    }

    public String getC1Num() {
        return c1Num;
    }

    public void setC1Num(String c1Num) {
        this.c1Num = s(c1Num);
    }

    public String getNoteNum() {
        return noteNum;
    }

    public void setNoteNum(String noteNum) {
        this.noteNum = s(noteNum);
    }

    public Date getC1PaymentDate() {
        return c1PaymentDate;
    }

    public void setC1PaymentDate(Date c1PaymentDate) {
        this.c1PaymentDate = c1PaymentDate;
    }

    public float getSum() {
        return sum;
    }

    public void setSum(float sum) {
        this.sum = sum;
    }

    public int getPositionsCount() {
        return positionsCount;
    }

    public void setPositionsCount(int positionsCount) {
        this.positionsCount = positionsCount;
    }

    public int getFirm() {
        return firm;
    }

    public void setFirm(int firm) {
        this.firm = firm;
    }

    public String getFirmAsString() {
        return Firm.asString(firm);
    }

    public long getStorekeeperId() {
        return storekeeperId;
    }

    public void setStorekeeperId(long storekeeperId) {
        this.storekeeperId = storekeeperId;
    }

    public java.util.Date getAssemblyDate() {
        return assemblyDate;
    }

    public void setAssemblyDate(java.util.Date assemblyDate) {
        this.assemblyDate = assemblyDate;
    }

    public String getAssemblyDateAsString() {
        if (assemblyDate == null) {
            return StringUtils.EMPTY;
        }
        return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(assemblyDate);
    }

    //
    //  ------------------------------------------------------------------------------------
    //

    //  section Более сложные статусы заказа

    private boolean getOrderStateIs(int orderState) {
        return getOrderStateId() == orderState;
    }

    /**
     * Заказ сохранен
     */
    public boolean getOrderStateIsPreSaved() {
        return getOrderStateIs(OrderState.PRE_SAVED);
    }

    /**
     * Заказ оформлен
     */
    public boolean getOrderStateIsSaved() {
        return getOrderStateIs(OrderState.SAVED);
    }

    /**
     * Заказ ожидает согласования
     */
    public boolean getOrderStateIsAwaitingValidation() {
        return getOrderStateIs(OrderState.AWAITING_VALIDATION);
    }

    /**
     * Заказ согласован
     */
    public boolean getOrderStateIsValidated() {
        return getOrderStateIs(OrderState.VALIDATED);
    }

    /**
     * Заказ не согласован
     */
    public boolean getOrderStateIsNotValidated() {
        return getOrderStateIs(OrderState.NOT_VALIDATED);
    }

    /**
     * Заказ принят бухгалтерией
     */
    public boolean getOrderStateIsAcceptedByBuh() {
        return getOrderStateIs(OrderState.ACCEPTED_BY_BUH);
    }

    /**
     * В ожидании команды на отгрузку от менеджера
     */
    public boolean getOrderStateIsAwaitingDelivery() {
        return getOrderStateIs(OrderState.AWAITING_DELIVERY);
    }

    /**
     * Заказ выдан на доставку
     */
    public boolean getOrderStateIsOnDelivery() {
        return getOrderStateIs(OrderState.DELIVERY);
    }

    public boolean getOrderStateIsOutput() {
        return getOrderStateIs(OrderState.OUTPUT);
    }

    /**
     * Обработка заказа завершена
     */
    public boolean getOrderStateIsComplete() {
        return getOrderStateIs(OrderState.COMPLETE);
    }

    /**
     * Текущий заказ допускается редактировать. Текущий заказ допускается редактировать, если он находится в одном из
     * статусов: - Предварительно сохранен - Оформлен - Не согласован - Ожидает согласования
     */
    public boolean getOrderIsEditable() {
        return getOrderStateIsPreSaved() ||
                getOrderStateIsSaved() ||
                getOrderStateIsNotValidated() ||
                getOrderStateIsAwaitingValidation();
    }

    /**
     * При переносе резервирования на сторону ИС менеджер может редактировать и удалять заказ до модтверждения его складом.
     * Статусы:
     * - Предварительно сохранен
     * - Оформлен (переименовать в зарезервирован)
     * - Не согласован
     * - Ожидает согласования
     * - Согласован
     * - На складе сборка
     * @return
     */
    public boolean getOrderIsEditableWithReserves(){
        return getOrderStateIsPreSaved() ||
                getOrderStateIsSaved() ||
                getOrderStateIsNotValidated() ||
                getOrderStateIsAwaitingValidation() ||
                getOrderStateIsOutput() ||
                getOrderStateIsValidated();
    }

    /**
     * Созвращает true, если состав заказа можно изменять. А состав заказа можно изменять только пока заказ находится в
     * статуах:
     * <p/>
     * OrderState.PRE_SAVED, OrderState.SAVED, OrderState.AWAITING_VALIDATION, OrderState.NOT_VALIDATED
     */
    public boolean getOrderStateIsBeforeSaved() {

        return getOrderStateIsPreSaved() ||
                getOrderStateIsSaved() ||
                getOrderStateIsAwaitingValidation() ||
                getOrderStateIsNotValidated();
    }


    //  -------------------------------------------------------------------------------------

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", clientId=" + clientId +
                ", managerId=" + managerId +
                ", orderStateId=" + orderStateId +
                ", deliveryTypeId=" + deliveryTypeId +
                ", orderTypeId=" + orderTypeId +
                ", deliveryTimeSpan=" + deliveryTimeSpan +
                ", deliveryAddress='" + deliveryAddress + '\'' +
                ", deliverySum=" + deliverySum +
                ", discountPercent=" + discountPercent +
                ", discountAbs=" + discountAbs +
                ", isDeleted=" + isDeleted +
                ", creationDate=" + creationDate +
                ", reservationDate=" + reservationDate +
                ", c1Num='" + c1Num + '\'' +
                ", noteNum='" + noteNum + '\'' +
                ", c1PaymentDate=" + c1PaymentDate +
                ", sum=" + sum +
                ", positionsCount=" + positionsCount +
                ", client=" + client +
                ", manager=" + manager +
                '}';
    }

    /**
     * Представить заказ в строки например: "Заказ #2 от 22.03.2010 14:00:23 на сумму 2050р."
     */
    public String toClientString() {
        SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
        return "Заказ #" + id + " от " + sdf.format(creationDate) + " на сумму " + String.valueOf(deliverySum + sum) + "р.";
    }

    public String toClientString(Client c) {
        if (c == null) {
            return toClientString();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
            return "Заказ клиента \"" + c.getCompanyName() + "\" #" + id + " от " + sdf.format(creationDate) + " на сумму " + String.valueOf(deliverySum + sum) + "р.";
        }
    }

    public boolean getDeliveryDateIsNull() {
        return deliveryDate == null;
    }

    public boolean getDeliveryDateIsExists() {
        return deliveryDate != null;
    }

    public boolean getDeliveryDateIsInPast() {
        if (getDeliveryDateIsNull()) {
            return false;
        }
        Calendar now = Calendar.getInstance();
        now.set(Calendar.HOUR_OF_DAY, 0);
        now.set(Calendar.MINUTE, 0);
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);
        return deliveryDate.getTime() < now.getTimeInMillis();
    }

    public boolean getReservationDateIsInPast() {
        if (getReservationDate() == null || !getOrderStateIsAwaitingValidation()) {
            return false;
        }
        Calendar now = Calendar.getInstance();
        now.set(Calendar.HOUR_OF_DAY, 0);
        now.set(Calendar.MINUTE, 0);
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);
        return reservationDate.getTime() < now.getTimeInMillis();
    }

    public String getFactDeliveryDateAsString() {
        if (factDeliveryDate == null) {
            return StringUtils.EMPTY;
        }
        return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(factDeliveryDate);
    }

    public boolean isFactDeliveryDateNull() {
        return factDeliveryDate == null;
    }

    public java.util.Date getAssemblyDateWithoutTime() {
        Calendar calendar = Calendar.getInstance();
        if (assemblyDate != null) {
            calendar.setTime(assemblyDate);
        }
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public boolean getOrderIsPrepareInTime() {
        return getAssemblyDateWithoutTime().before(getExpectedAssembyDate());
    }

    public java.util.Date getFactDeliveryDateWithoutTime(){
        Calendar calendar = Calendar.getInstance();
        if (factDeliveryDate != null) {
            calendar.setTime(factDeliveryDate);
        }
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    public boolean getOrderIsDeliveryInTime() {
        if(getFactDeliveryDateWithoutTime().before(getDeliveryDateForPreparingWithFactDeliveryDate())) return true;
        return getFactDeliveryDateWithoutTime().before(getExpectedDeliveryDate());
    }

    public java.util.Date getDeliveryDateForPreparingWithFactDeliveryDate(){
        Calendar deliveryDateForPreparing = Calendar.getInstance();
        deliveryDateForPreparing.setTime(deliveryDate);
        deliveryDateForPreparing.set(Calendar.HOUR_OF_DAY, 23);
        deliveryDateForPreparing.set(Calendar.MINUTE, 59);
        deliveryDateForPreparing.set(Calendar.SECOND, 59);
        return deliveryDateForPreparing.getTime();
    }
}
